package com.lmmob.autotest.uitest.pages;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Action;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.internal.seleniumemulation.AlertOverride;
import org.openqa.selenium.internal.seleniumemulation.JavascriptLibrary;
import org.openqa.selenium.internal.seleniumemulation.Timer;
import org.openqa.selenium.internal.seleniumemulation.Windows;
import org.openqa.selenium.remote.Augmenter;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Throwables;
import com.lmmob.autotest.uitest.assertions.ResultVerifier;
import com.lmmob.autotest.uitest.exception.BaseException;
import com.lmmob.autotest.uitest.exception.CheckException;
import com.thoughtworks.selenium.SeleniumException;
import com.thoughtworks.selenium.Wait;

import javax.annotation.Nullable;

import java.awt.AWTException;
import java.awt.Robot;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public abstract class BasePage {

	private final Logger log = LoggerFactory.getLogger(BasePage.class);

	protected WebDriver driver;
	private JavascriptLibrary js = new JavascriptLibrary();
	private final JavascriptLibrary library = new JavascriptLibrary();;
	private ElementFinder finder;
	private final Timer timer = new Timer(3000);
	private String actualValue = "";
	private String expectValue = "";
	private String exceptionMessage = "";
	private String message = "";

	public BasePage(WebDriver webDriver) {
		this.driver = webDriver;
		finder=new ElementFinder(webDriver);
	}

	public void go(String baseUrl) {
		if(getUrl().contains("http://")){
			driver.get(getUrl());
		}else{
			driver.get(baseUrl + getUrl());
		}
	}

	public String getUrl() {
		return StringUtils.EMPTY;
	}

	protected WebElement findElement(final By by) {
		WebDriverWait wait = new WebDriverWait(driver, 8);
		wait.until(new ExpectedCondition<WebElement>() {
			public WebElement apply(@Nullable WebDriver webDriver) {
				return webDriver.findElement(by);
			}
		});
		return driver.findElement(by);
	}

	protected void dbClick(WebElement element) {
		Actions builder = new Actions(driver);
		Action dbClick = builder.doubleClick(element).build();
		dbClick.perform();
	}

	protected void waitAWhile(long period, TimeUnit unit) {
		try {
			unit.sleep(period);
		} catch (InterruptedException e) {

		}
	}

	public void waitForCondition(String script, String timeout) {

		StringBuilder builder = new StringBuilder();
		builder.append(script);
		final String modified = builder.toString();

		new Wait() {
			@Override
			public boolean until() {
				Object result = ((JavascriptExecutor) driver)
						.executeScript(modified);

				// Although the conditions should return a boolean, JS has a
				// loose
				// definition of "true" Try and meet that definition.
				if (result == null) {
					return false;
				} else if (result instanceof String) {
					return !"".equals(result);
				} else if (result instanceof Boolean) {
					return (Boolean) result;
				} else {
					return true;
				}
			}
		}.wait("Failed to resolve " + script, Long.valueOf(timeout));
	}

	public void setTimeout(String timeout) {

		if ("0".equals(timeout)) {
			timer.setTimeout(Long.MAX_VALUE);
		} else {
			timer.setTimeout(Long.parseLong(timeout));
		}
	}

	public void waitForPageToLoad(String timeout) {

		if (!(driver instanceof JavascriptExecutor)) {
			// Assume that we Do The Right Thing
			return;
		}
		long timeoutInMillis = Long.parseLong(timeout);
		// Micro sleep before we continue in case an async click needs
		// processing.
		pause();
		Object result = ((JavascriptExecutor) driver)
				.executeScript("return !!document['readyState'];");
		log.info("Does browser support readyState: " + result);

		Wait wait = (result != null && (Boolean) result) ? getReadyStateUsingWait(driver)
				: getLengthCheckingWait(driver);

		wait.wait(String.format("Failed to load page within %s ms", timeout),
				timeoutInMillis);

		pause();

		return;
	}

	private void pause() {
		try {
			Thread.sleep(250);
		} catch (InterruptedException e) {
			throw Throwables.propagate(e);
		}
	}

	public void waitForPopup(final String windowID, String timeout) {

		final long millis = Long.parseLong(timeout);
		final String current = driver.getWindowHandle();
		final Windows windows = new Windows(driver);
		new Wait() {
			@Override
			public boolean until() {
				try {
					if ("_blank".equals(windowID)) {
						windows.selectBlankWindow(driver);
					} else {
						driver.switchTo().window(windowID);
					}
					return !"about:blank".equals(driver.getCurrentUrl());
				} catch (SeleniumException e) {
					// Swallow
				}
				return false;
			}
		}.wait(String.format("Timed out waiting for %s. Waited %s", windowID,
				timeout), millis);

		driver.switchTo().window(current);

		return;
	}

	public void windowMaximize() {

		JavascriptLibrary js = new JavascriptLibrary();
		js.executeScript(
				driver,
				"if (window.screen) { window.moveTo(0, 0); window.resizeTo(window.screen.availWidth, window.screen.availHeight);};");

		return;
	}

	public void windowFocus() {

		JavascriptLibrary js = new JavascriptLibrary();
		js.executeScript(driver, "window.focus()");
		return;
	}

	public boolean isElementPresent(String locator) {

		WebElement element = null;
		try {
			element = finder.findElement(locator);
		} catch (Exception e) {

			log.info(e.getMessage());
		}
		if (element != null) {
			return true;
		}
		{
			return false;
		}
	}

	public String getTitle() {
		return driver.getTitle();
	}

	private Wait getReadyStateUsingWait(final WebDriver driver) {
		return new Wait() {
			public boolean until() {
				try {
					Object result = ((JavascriptExecutor) driver)
							.executeScript("return 'complete' == document.readyState;");

					if (result != null && result instanceof Boolean
							&& (Boolean) result) {
						return true;
					}
				} catch (Exception e) {
					// Possible page reload. Fine
				}
				return false;
			}
		};
	}

	public void click(String locator) {
		WebElement element = finder.findElement(locator);
		if (element != null) {
			element.click();
		}
	}

	// Sets the value of an input field, as though you typed it in
	public void type(String locator, String value) {
		WebElement element = finder.findElement(locator);
		element.sendKeys(Keys.TAB + "");
		element.clear();
		element.sendKeys(value);
	}

	/**
	 * label先去掉空格在进行比较
	 * @param dropDownLocator
	 * @param optionSpecifier
	 */
	// Select an option from a drop-down using an option locator
	public void select(String dropDownLocator, String optionSpecifier) {
		WebElement element = finder.findElement(dropDownLocator);
		List<WebElement> options = element.findElements(By.tagName("option"));
		{
			for (WebElement option : options) {
				String text=option.getText();
				if (optionSpecifier.equalsIgnoreCase(text.trim())) {
					option.click();
				}
			}
		}
	}

	// Simulates the user clicking the "back" button on their browser
	public void goBack() {
		driver.navigate().back();
	}

	public void forward() {

		driver.navigate().forward();
	}

	public void selectWindow(String nameOrHandle) {
		Windows windows = new Windows(driver);
		windows.selectWindow(driver, nameOrHandle);
	}

	public void selectPopUp(String windowID) {
		driver.switchTo().window(windowID);
	}

	public void doubleClick(String locator) {
		WebElement element = finder.findElement(locator);
		if (element != null) {
			Actions actions = new Actions(driver);
			actions.doubleClick(element);
			// actions.build().perform()
		}
	}

	public void doubleClickAt(String locator, String coordString) {

	}

	public void clickAt(String locator, String coordString) {

	}
	
	public void upload(String locator,String filepath){
		WebElement element = finder.findElement(locator);
		element.sendKeys(filepath);
	}

	public void submit(String formlocator) {
		WebElement element = finder.findElement(formlocator);
		element.submit();
	}

	public void typeKeys(String locator, String value) {
		WebElement element = finder.findElement(locator);
		// element.sendKeys(value);
		// element.sendKeys(Keys.TAB);
		element.sendKeys(value);
	}

	public void attachFile(String fieldLocator, String fileLocator) {

		WebElement element = finder.findElement(fieldLocator);
		File file = new File(fileLocator);
		if (element != null) {
			log.info(file.getAbsolutePath());
			element.sendKeys(file.getAbsolutePath());
		}
	}

	public void chooseCancelOnNextConfirmation() {

		Alert alert = driver.switchTo().alert();
		alert.dismiss();
	}

	public void chooseOkOnNextConfirmation() {

		Alert alert = driver.switchTo().alert();
		alert.accept();
	}

	public void dragdrop(String locator, String movementsString) {

	}

	public void dragAndDropToObject(String locatorOfObjectToBeDragged,
			String locatorOfDragDestinationObject) {

	}

	// dragAndDrop("id","50,20")
	public void dragAndDrop(String locator, String movementsString) {

		WebElement element = finder.findElement(locator);
		int xOffset = Integer.parseInt(movementsString.split(",")[0]);
		int yOffset = Integer.parseInt(movementsString.split(",")[1]);
		if (element != null) {
			Actions actions = new Actions(driver);
			actions.dragAndDropBy(element, xOffset, yOffset);
		}
	}

	public void refresh() {

		driver.navigate().refresh();
	}

	public void runScript(String script) {
		((JavascriptExecutor) driver).executeScript(script);
	}

	public String getAlert() {
		Alert alert = driver.switchTo().alert();
		return alert.getText();
	}
	
	public void clickAlert(){
		Alert alert = driver.switchTo().alert();
		alert.accept();
	}

	public void selectFrame(String frameID) {
		if(frameID.equals("relative=top")||frameID.equals("top"))
		{
			driver.switchTo().defaultContent();
			return;
		}
		driver.switchTo().frame(frameID);		
	}

	public boolean isChecked(String locator) {
		WebElement element = finder.findElement(locator);
		return element.isSelected();
	}

	// Simulates the user clicking the "close" button in the titlebar of a popup
	// window or tab
	public void close() {
		driver.close();
	}

	public String[] getAllButtons() {

		List<WebElement> allInputs = driver.findElements(By.xpath("//input"));
		List<String> ids = new ArrayList<String>();

		for (WebElement input : allInputs) {
			String type = input.getAttribute("type").toLowerCase();
			if ("button".equals(type) || "submit".equals(type)
					|| "reset".equals(type))
				ids.add(input.getAttribute("id"));
		}

		return ids.toArray(new String[ids.size()]);

	}

	public String[] getAllFields() {
		List<WebElement> allInputs = driver.findElements(By.xpath("//input"));
		List<String> ids = new ArrayList<String>();

		for (WebElement input : allInputs) {
			String type = input.getAttribute("type").toLowerCase();
			if ("text".equals(type))
				ids.add(input.getAttribute("id"));
		}

		return ids.toArray(new String[ids.size()]);
	}

	public String[] getAllLinks() {
		List<WebElement> allLinks = driver.findElements(By.xpath("//a"));
		Iterator<WebElement> i = allLinks.iterator();
		List<String> links = new ArrayList<String>();
		while (i.hasNext()) {
			WebElement link = i.next();
			String id = link.getAttribute("id");
			if (id == null)
				links.add("");
			else
				links.add(id);
		}

		return links.toArray(new String[links.size()]);
	}

	public String[] getAllWindowIds() {

		return this.getAttributeFromAllWindows("id");
	}

	public String[] getAllWindowNames() {

		return this.getAttributeFromAllWindows("name");
	}

	public String[] getAllWindowTitles() {

		String current = driver.getWindowHandle();

		List<String> attributes = new ArrayList<String>();
		for (String handle : driver.getWindowHandles()) {
			driver.switchTo().window(handle);
			attributes.add(driver.getTitle());
		}

		driver.switchTo().window(current);

		return attributes.toArray(new String[attributes.size()]);
	}

	public String getAttribute(String attributeLocator) {

		JavascriptLibrary library = new JavascriptLibrary();
		String getAttribute = "return ("
				+ library.getSeleniumScript("getAttribute.js")
				+ ").apply(null, arguments);";
		try {
			return (String) library.executeScript(driver, getAttribute,
					attributeLocator);
		} catch (WebDriverException e) {
			String[] nameAndAttribute = getNameAndAttribute(attributeLocator);

			WebElement element = finder.findElement(nameAndAttribute[0]);
			return element.getAttribute(nameAndAttribute[1]);
		}
	}

	@VisibleForTesting
	protected String[] getNameAndAttribute(String attributeLocator) {
		int atSign = attributeLocator.lastIndexOf("@");

		String[] toReturn = new String[2];

		toReturn[0] = attributeLocator.substring(0, atSign);
		toReturn[1] = attributeLocator.substring(atSign + 1);

		return toReturn;
	}

	public String[] getAttributeFromAllWindows(String attributeName) {

		String current = driver.getWindowHandle();

		List<String> attributes = new ArrayList<String>();
		for (String handle : driver.getWindowHandles()) {
			driver.switchTo().window(handle);
			String value = (String) ((JavascriptExecutor) driver)
					.executeScript("return '' + window[arguments[0]];",
							attributeName);
			attributes.add(value);
		}

		driver.switchTo().window(current);

		return attributes.toArray(new String[attributes.size()]);
	}

	public String getBodyText() {

		return driver.findElement(By.xpath("//body")).getText();
	}

	public String getConfirmation() {

		AlertOverride alertOverride = new AlertOverride();
		return alertOverride.getNextConfirmation(driver);

	}

	public String getCookie() {

		StringBuilder builder = new StringBuilder();
		for (Cookie c : driver.manage().getCookies()) {
			builder.append(c.toString());
			builder.append("; ");
		}
		return builder.toString();
	}

	public String getCookieByName(String name) {

		Cookie cookie = driver.manage().getCookieNamed(name);
		return cookie == null ? null : cookie.getValue();
	}

	public int getCssCount(String css) {

		return driver.findElements(By.cssSelector(css)).size();
	}

	public int getCursorPosition(String locator) {

		return 0;
	}

	public int getElementHeight(String locator) {

		Dimension size = finder.findElement(locator).getSize();
		return size.getHeight();
	}

	public int getElementIndex(String locator) {

		WebElement element = finder.findElement(locator);
		JavascriptLibrary js = new JavascriptLibrary();
		String script = "var _isCommentOrEmptyTextNode = function(node) {\n"
				+ "    return node.nodeType == 8 || ((node.nodeType == 3) && !(/[^\\t\\n\\r ]/.test(node.data)));\n"
				+ "};\n"
				+ "    var element = arguments[0];\n"
				+ "    var previousSibling;\n"
				+ "    var index = 0;\n"
				+ "    while ((previousSibling = element.previousSibling) != null) {\n"
				+ "        if (!_isCommentOrEmptyTextNode(previousSibling)) {\n"
				+ "            index++;\n" + "        }\n"
				+ "        element = previousSibling;\n" + "    }\n"
				+ "    return index;";

		return (Integer) js.executeScript(driver, script, element);
	}

	public int getElementPositionLeft(String locator) {

		Point location = finder.findElement(locator).getLocation();
		return location.getX();
	}

	public int getElementPositionTop(String locator) {

		Point location = finder.findElement(locator).getLocation();
		return location.getY();
	}

	public int getElementWidth(String locator) {

		Dimension size = finder.findElement(locator).getSize();
		return size.getWidth();
	}

	public String getEval(String script) {

		Object result = ((JavascriptExecutor) driver).executeScript(script);
		return result == null ? "" : String.valueOf(result);
	}

	public String getExpression(String expression) {

		return expression;
	}

	public String getHtmlSource() {

		return driver.getPageSource();
	}

	public String getLocation() {

		return driver.getCurrentUrl();
	}

	public String getSelectedId(String selectLocator) {

		return findSelectedOptionProperties(selectLocator, "id")[0];
	}

	private List<WebElement> getOptions(String selectLocator) {
		WebElement element = finder.findElement(selectLocator);
		List<WebElement> options = element.findElements(By.tagName("option"));
		if (options.size() == 0) {
			throw new SeleniumException(
					"Specified element is not a Select (has no options)");
		}
		return options;
	}

	private String[] findSelectedOptionProperties(String selectLocator,
			String property) {
		List<WebElement> options = getOptions(selectLocator);

		List<String> selectedOptions = new ArrayList<String>();

		for (WebElement option : options) {
			if (option.isSelected()) {
				if ("text".equals(property)) {
					selectedOptions.add(option.getText());
				} else {
					String propVal = option.getAttribute(property);
					if (propVal != null)
						selectedOptions.add(propVal);
				}
			}
		}

		if (selectedOptions.size() == 0)
			throw new SeleniumException("No option selected");
		return selectedOptions.toArray(new String[selectedOptions.size()]);
	}

	public String[] getSelectedIds(String selectLocator) {

		return findSelectedOptionProperties(selectLocator, "id");
	}

	public String getSelectedIndex(String selectLocator) {
		List<WebElement> options = getOptions(selectLocator);
		for (int i = 0; i < options.size(); i++) {
			WebElement option = options.get(i);
			if (option.isSelected())
				return String.valueOf(i);
		}
		throw new SeleniumException("No option is selected: " + selectLocator);
	}

	public String[] getSelectedIndexes(String selectLocator) {

		List<WebElement> options = getOptions(selectLocator);
		List<String> selected = new ArrayList<String>();
		for (int i = 0; i < options.size(); i++) {
			WebElement option = options.get(i);
			if (option.isSelected())
				selected.add(String.valueOf(i));
		}
		return selected.toArray(new String[selected.size()]);
	}

	public String getSelectedLabel(String selectLocator) {

		String[] labels = findSelectedOptionProperties(selectLocator, "text");
		return labels[0]; // Since we know that there must have been at least
							// one thing selected
	}

	public String[] getSelectedLabels(String selectLocator) {

		return findSelectedOptionProperties(selectLocator, "text");
	}

	public String getSelectedValue(String selectLocator) {

		return findSelectedOptionProperties(selectLocator, "value")[0];

	}

	public String[] getSelectedValues(String selectLocator) {

		return findSelectedOptionProperties(selectLocator, "value");
	}

	public String[] getSelectOptions(String selectLocator) {
		WebElement select = finder.findElement(selectLocator);
		List<WebElement> options = select.findElements(By.tagName("option"));
		List<String> optionValues = new ArrayList<String>();
		for (WebElement option : options) {
			optionValues.add(option.getText());
		}
		return optionValues.toArray(new String[optionValues.size()]);
	}

	public void stop() {

		driver.quit();
	}

	public String getSpeed() {

		throw new UnsupportedOperationException("getSpeed");
	}

	public String getTable(String tableCellAddress) {
		Pattern TABLE_PARTS = Pattern.compile("(.*)\\.(\\d+)\\.(\\d+)");
		Matcher matcher = TABLE_PARTS.matcher(tableCellAddress);
		if (!matcher.matches()) {
			throw new SeleniumException(
					"Invalid target format. Correct format is tableName.rowNum.columnNum");
		}
		String tableName = matcher.group(1);
		long row = Long.parseLong(matcher.group(2));
		long col = Long.parseLong(matcher.group(3));

		WebElement table = finder.findElement(tableName);

		String script = "var table = arguments[0]; var row = arguments[1]; var col = arguments[2];"
				+ "if (row > table.rows.length) { return \"Cannot access row \" + row + \" - table has \" + table.rows.length + \" rows\"; }"
				+ "if (col > table.rows[row].cells.length) { return \"Cannot access column \" + col + \" - table row has \" + table.rows[row].cells.length + \" columns\"; }"
				+ "return table.rows[row].cells[col];";

		Object value = executeScript(script, table, row, col);
		if (value instanceof WebElement) {
			return ((WebElement) value).getText().trim();
		}

		throw new SeleniumException((String) value);

	}
	
	/**
	 * 获取table中的某一行，用法：//table.1表示第2行
	 * @param tableRowAddress
	 * @return
	 */
	public String getTableRow(String tableRowAddress) {
		Pattern TABLE_PARTS = Pattern.compile("(.*)\\.(\\d+)");
		Matcher matcher = TABLE_PARTS.matcher(tableRowAddress);
		if (!matcher.matches()) {
			throw new SeleniumException(
					"Invalid target format. Correct format is tableName.rowNum");
		}
		String tableName = matcher.group(1);
		long row = Long.parseLong(matcher.group(2));

		WebElement table = finder.findElement(tableName);

		String script = "var table = arguments[0]; var row = arguments[1]; var col = arguments[2];"
				+ "if (row > table.rows.length) { return \"Cannot access row \" + row + \" - table has \" + table.rows.length + \" rows\"; }"
				+ "if (col > table.rows[row].cells.length) { return \"Cannot access column \" + col + \" - table row has \" + table.rows[row].cells.length + \" columns\"; }"
				+ "return table.rows[row];";

		Object value = executeScript(script, table, row);
		if (value instanceof WebElement) {
			String text=((WebElement) value).getText().trim();
			//去掉空格、制表符、换页符等空白字符
			text = text.replaceAll("\\s*", "");
			return text;
		}
		throw new SeleniumException((String) value);
	}
	
	public String getTableRowNum(String tableName){
		WebElement table = finder.findElement(tableName);
		String script = "var table = arguments[0];return table.rows.length;";
		Object value = executeScript(script, table);
		if (value instanceof Long) {
			return String.valueOf(value);
		}
		throw new SeleniumException(String.valueOf(value));		
	}

	private Object executeScript(String script, Object... args) {
		if (driver instanceof JavascriptExecutor) {
			return ((JavascriptExecutor) driver).executeScript(script, args);
		}

		throw new UnsupportedOperationException(
				"The underlying WebDriver instance does not support executing javascript");
	}

	public String getText(String locator) {

		return finder.findElement(locator).getText().trim();
	}

	public String getValue(String locator) {

		return finder.findElement(locator).getAttribute("value");
	}

	public boolean getWhetherThisFrameMatchFrameExpression(
			String currentFrameString, String target) {

		throw new UnsupportedOperationException(
				"getWhetherThisFrameMatchFrameExpression");
	}

	public boolean getWhetherThisWindowMatchWindowExpression(
			String currentWindowString, String target) {

		throw new UnsupportedOperationException(
				"getWhetherThisWindowMatchWindowExpression");
	}

	public int getXpathCount(String xpath) {

		if (xpath.startsWith("xpath=")) {
			xpath = xpath.substring("xpath=".length());
		}
		return driver.findElements(By.xpath(xpath)).size();
	}

	public boolean isAlertPresent() {

		WebDriverWait wait = new WebDriverWait(driver, 300 /*timeout in seconds*/);
		 if(wait.until(ExpectedConditions.alertIsPresent())==null)
		       return false;
		 else
		       return true;
		//AlertOverride alertOverride = new AlertOverride();
		//return alertOverride.isAlertPresent(driver);
	}

	public boolean isConfirmationPresent() {

		AlertOverride alertOverride = new AlertOverride();
		return alertOverride.isConfirmationPresent(driver);
	}

	public boolean isCookiePresent(String name) {

		return driver.manage().getCookieNamed(name) == null ? false : true;
	}

	public boolean isEditable(String locator) {

		WebElement element = finder.findElement(locator);
		String tagName = element.getTagName().toLowerCase();
		boolean acceptableTagName = "input".equals(tagName)
				|| "select".equals(tagName);
		String readonly = "";
		if ("input".equals(tagName)) {
			readonly = element.getAttribute("readonly");
			if (readonly == null || "false".equals(readonly)) {
				readonly = "";
			}
		}

		return element.isEnabled() && acceptableTagName && "".equals(readonly);
	}

	public boolean isOrdered(String locator1, String locator2) {

		WebElement one = finder.findElement(locator1);
		WebElement two = finder.findElement(locator2);
		String ordered = "    if (arguments[0] === arguments[1]) return false;\n"
				+ "\n"
				+ "    var previousSibling;\n"
				+ "    while ((previousSibling = arguments[1].previousSibling) != null) {\n"
				+ "        if (previousSibling === arguments[0]) {\n"
				+ "            return true;\n"
				+ "        }\n"
				+ "        arguments[1] = previousSibling;\n"
				+ "    }\n"
				+ "    return false;\n";
		Boolean result = (Boolean) executeScript(ordered, one, two);
		return result == null ? false : result.booleanValue();
	}

	public boolean isPromptPresent() {

		throw new UnsupportedOperationException("isPromptPresent");
	}

	public boolean isSomethingSelected(String selectLocator) {

		WebElement select = finder.findElement(selectLocator);
		String tagName = select.getTagName().toLowerCase();
		if (!"select".equals(tagName)) {
			throw new SeleniumException("Specified element is not a Select");
		}
		for (WebElement option : select.findElements(By.tagName("option"))) {
			if (option.isSelected()) {
				return true;
			}
		}
		return false;
	}

	public boolean isTextPresent(String pattern) {

		String text = driver.getPageSource();
		text = text.trim();
		if (text.contains(pattern)) {
			return true;
		}
		return false;
	}

	public boolean isVisible(String locator) {

		return finder.findElement(locator).isDisplayed();
	}

	public void keyDown(String locator, String keySequence) {

		// js.callEmbeddedSelenium(driver,"doKeyDown",
		// finder.findElement(locator), keySequence, controlKeyDown, altKeyDown,
		// shiftKeyDown, metaKeyDown);
	}

	public void keyUp(String locator, String keySequence) {

		// js.callEmbeddedSelenium(driver,"doKeyUp",
		// finder.findElement(locator), keySequence, controlKeyDown, altKeyDown,
		// shiftKeyDown, metaKeyDown);
	}

	public void mouseOver(String locator) {

		/*String fire = "return (" + js.getSeleniumScript("fireEvent.js")
				+ ").apply(null, arguments);";
		WebElement element = finder.findElement(locator);
		js.executeScript(driver, fire, element, "mouseOver");*/
		WebElement element = finder.findElement(locator);
		String code = "var fireOnThis = arguments[0];"
                + "var evObj = document.createEvent('MouseEvents');"
                + "evObj.initEvent( 'mouseover', true, true );"
                + "fireOnThis.dispatchEvent(evObj);";
		((JavascriptExecutor) driver).executeScript(code, element);
	}

	public void mouseOut(String locator) {

		String fire = "return (" + js.getSeleniumScript("fireEvent.js")
				+ ").apply(null, arguments);";
		WebElement element = finder.findElement(locator);
		js.executeScript(driver, fire, element, "mouseOut");
	}

	public void mouseDown(String locator) {

		String fire = "return (" + js.getSeleniumScript("fireEvent.js")
				+ ").apply(null, arguments);";
		WebElement element = finder.findElement(locator);
		js.executeScript(driver, fire, element, "mouseDown");
	}

	public void mouseDownRight(String locator) {

		String fire = "return (" + js.getSeleniumScript("fireEvent.js")
				+ ").apply(null, arguments);";
		WebElement element = finder.findElement(locator);
		js.executeScript(driver, fire, element, "mouseDownRight");
	}

	public void mouseDownAt(String locator, String coordString) {

		String fire = "return (" + js.getSeleniumScript("fireEvent.js")
				+ ").apply(null, arguments);";
		WebElement element = finder.findElement(locator);
		js.executeScript(driver, fire, element, "mouseDown", coordString);
	}

	public void mouseDownRightAt(String locator, String coordString) {

		String fire = "return (" + js.getSeleniumScript("fireEvent.js")
				+ ").apply(null, arguments);";
		WebElement element = finder.findElement(locator);
		js.executeScript(driver, fire, element, "mouseDownRight", coordString);
	}

	public void mouseUp(String locator) {

		String fire = "return (" + js.getSeleniumScript("fireEvent.js")
				+ ").apply(null, arguments);";
		WebElement element = finder.findElement(locator);
		js.executeScript(driver, fire, element, "mouseUp");
	}

	public void mouseUpRight(String locator) {

		String fire = "return (" + js.getSeleniumScript("fireEvent.js")
				+ ").apply(null, arguments);";
		WebElement element = finder.findElement(locator);
		js.executeScript(driver, fire, element, "mouseUpRight");
	}

	public void mouseUpAt(String locator, String coordString) {

		String fire = "return (" + js.getSeleniumScript("fireEvent.js")
				+ ").apply(null, arguments);";
		WebElement element = finder.findElement(locator);
		js.executeScript(driver, fire, element, "mouseUp", coordString);
	}

	public void mouseUpRightAt(String locator, String coordString) {

		String fire = "return (" + js.getSeleniumScript("fireEvent.js")
				+ ").apply(null, arguments);";
		WebElement element = finder.findElement(locator);
		js.executeScript(driver, fire, element, "mouseUpRight", coordString);
	}

	public void mouseMove(String locator) {

		String fire = "return (" + js.getSeleniumScript("fireEvent.js")
				+ ").apply(null, arguments);";
		WebElement element = finder.findElement(locator);
		js.executeScript(driver, fire, element, "mouseMove");
	}

	private void removeAllSelections(List<WebElement> options) {
		for (WebElement option : options) {
			if (option.isSelected())
				option.click();
		}
	}

	public void removeAllSelections(String locator) {

		WebElement select = finder.findElement(locator);
		List<WebElement> options = select.findElements(By.tagName("option"));

		String multiple = select.getAttribute("multiple");
		if (multiple == null || "".equals(multiple)) {
			return;
		}

		removeAllSelections(options);

		return;
	}

	public void removeScript(String arg0) {

		throw new UnsupportedOperationException(
				"Selenium.removeScript() not implemented yet.");
	}

	public void removeSelection(String locator, String optionLocator) {

		String findOption = "return ("
				+ library.getSeleniumScript("findOption.js")
				+ ").apply(null, arguments)";
		WebElement select = finder.findElement(locator);
		if (!"select".equals(select.getTagName().toLowerCase())) {
			throw new SeleniumException("Element is not a select element: "
					+ locator);
		}
		WebElement option = (WebElement) ((JavascriptExecutor) driver)
				.executeScript(findOption, select, optionLocator);
		;
		if (option.isSelected()) {
			option.click();
		}
	}

	public void mouseMoveAt(String locator, String coordString) {

		String fire = "return (" + js.getSeleniumScript("fireEvent.js")
				+ ").apply(null, arguments);";
		WebElement element = finder.findElement(locator);
		js.executeScript(driver, fire, element, "mouseMove", coordString);
	}

	public void sleep(long millis) {

		try {
			Thread.sleep(millis);
		} catch (InterruptedException e) {

			e.printStackTrace();
		}
	}

	public void captureEntirePageScreenshotToFile(String file, String kwargs) {
		try {
			captureScreenshot(file);
			// 对于remotewebdriver会出现异常，得用以下代码进行截图
		} catch (ClassCastException e) {

			WebDriver augmentedDriver = new Augmenter().augment(driver);
			byte[] scrFile = ((TakesScreenshot) augmentedDriver)
					.getScreenshotAs(OutputType.BYTES);
			try {
				FileUtils.writeByteArrayToFile(new File(file), scrFile);
			} catch (IOException e1) {

				e1.printStackTrace();
			}
		}
	}

	public void captureScreenshot(String filename) {

		byte[] scrFile = ((TakesScreenshot) driver)
				.getScreenshotAs(OutputType.BYTES);
		try {
			FileUtils.writeByteArrayToFile(new File(filename), scrFile);
		} catch (IOException e) {

			e.printStackTrace();
		}
	}

	public void keyPressNative(String keycode) {
		// 自动触发事件
		Robot robot = null;
		try {
			robot = new Robot();
		} catch (AWTException e) {

			e.printStackTrace();
		}
		for (int i = 0; i < keycode.length(); i++) {

			char code = keycode.charAt(i);
			robot.keyPress((int) code - 32);

			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {

				log.info(e.getMessage());
			}
		}
	}
	
	public void verifyAttribute(String attributeLocator, String attributeName,
			String pattern) throws Exception {
		
		
		actualValue = this.getAttribute(attributeName);
		verify(pattern, actualValue);
	}
	
	public void verifyTitle(String patten) throws Exception {
		actualValue = this.getTitle();
		verify(patten, actualValue);
	}



	public void verifyBodyText(String pattern) throws Exception {
		
		actualValue = this.getBodyText();
		verify(pattern, actualValue);
	}
	
	public void verifyText(String locator, String patten) throws Exception {
		actualValue = this.getText(locator);
		verify(patten, actualValue);
	}
	
	public void verifyValue(String locator, String patten) throws Exception {
		actualValue = this.getValue(locator);
		verify(patten, actualValue);
	}
	
	public void verifyStringByExist(String patten,String actualValue) throws Exception{
		verify(patten, actualValue);
	}


	public void verifyChecked(String locator) throws Exception {
		
		boolean value = this.isChecked(locator);
		if (value) {
			log.info("the checkbox is checked!");
		} else {
			log.error("the checkbox is not checked!");
			throw new CheckException("the checkbox is not checked!");
		}
	}


	public void verifyCookie(String patten) throws Exception {
		
		actualValue = this.getCookie();
		verify(patten, actualValue);
	}

	public void verifyElementHeight(String locator, String patten)
			throws Exception {
		
		Number value = this.getElementHeight(locator);
		verify(patten, String.valueOf(value));
	}


	public void verifyElementIndex(String locator, String patten)
			throws Exception {
		
		Number value = this.getElementIndex(locator);
		verify(patten, String.valueOf(value));
	}


	public void verifyElementPresent(String locator) throws Exception {
		
		boolean value = this.isElementPresent(locator);
		if (value) {
			log.info("the Element is Present!");
		} else {
			log.error("the Element is not Present!");
			throw new CheckException("the Element is not Present!");
		}
	}


	public void verifyElementNotPresent(String locator) throws Exception {
		
		boolean value = isElementPresent(locator);
		if (!value) {
			log.info("the Element is not Present!");
		} else {
			log.error("the Element is Present!");
			throw new CheckException("the Element is Present!");
		}
	}


	public void verifyElementWidth(String locator, String patten)
			throws Exception {
		
		Number value = getElementWidth(locator);
		verify(patten, String.valueOf(value));
	}


	public void verifyHtmlSource(String patten) throws Exception {
		
		actualValue = getHtmlSource();
		verify(patten, actualValue);
	}


	public void verifyLocation(String patten) throws Exception {
		
		actualValue = getLocation();
		verify(patten, actualValue);
	}


	public void verifySelectedId(String locator, String patten)
			throws Exception {
		
		actualValue = getSelectedId(locator);
		verify(patten, actualValue);
	}


	public void verifySelectedIds(String locator, String patten)
			throws Exception {
		
		String array1[] = getSelectedIds(locator);
		String array2[] = patten.split("|");
		if (array1.equals(array2)) {
			log.info("the SelectedIds match the actualValue!");
		} else {
			log.error("the SelectedIds don't match the actualValue!");
			throw new CheckException(
					"the SelectedIds don't match the actualValue!");
		}
	}


	public void verifySelectedIndex(String locator, String patten)
			throws Exception {
		
		actualValue = getSelectedIndex(locator);
		verify(patten, actualValue);
	}


	public void verifySelectedIndexes(String locator, String patten)
			throws Exception {
		
		String array1[] = getSelectedIndexes(locator);
		String array2[] = patten.split("|");
		if (array1.equals(array2)) {
			log.info("the SelectedIndexes match the actualValue!");
		} else {
			log.error("the SelectedIndexes don't match the actualValue!");
			throw new CheckException(
					"the SelectedIndexes don't match the actualValue!");
		}
	}


	public void verifySelectedLabel(String locator, String patten)
			throws Exception {
		
		actualValue = getSelectedLabel(locator);
		verify(patten, actualValue);
	}

	public void verifySelectedLabels(String locator, String patten)
			throws Exception {
		
		String array1[] = getSelectedLabels(locator);
		String array2[] = patten.split("|");
		if (array1.equals(array2)) {
			log.info("the SelectedLabels( match the actualValue!");
		} else {
			log.error("the SelectedLabels don't match the actualValue!");
			throw new CheckException(
					"the SelectedLabels don't match the actualValue!");
		}
	}


	public void verifySelectedValue(String locator, String patten)
			throws Exception {
		
		actualValue = getSelectedValue(locator);
		verify(patten, actualValue);
	}


	public void verifySelectOptions(String locator, String patten)
			throws Exception {
		
		String array1[] = getSelectOptions(locator);
		String array2[] = patten.split("|");
		if (array1.equals(array2)) {
			log.info("the SelectOptions( match the actualValue!");
		} else {
			log.error("the SelectOptions don't match the actualValue!");
			throw new CheckException(
					"the SelectedLabels don't match the actualValue!");
		}
	}


	public void verifyTable(String tableCellAddress, String patten)
			throws Exception {
		
		actualValue = this.getTable(tableCellAddress);
		verify(patten, actualValue);
	}
	
	private void verify(String pattern, String actualValue) throws Exception {
		this.actualValue = actualValue;
		//this.expectValue=pattern;
		this.setExceptionMessage(actualValue,pattern);
		this.setMessage(pattern, actualValue);
		String errormsg = getExceptionMessage();
		String msg = getMessage();
		if (ResultVerifier.verifyStringsByEqualAndExist(pattern, actualValue)) {
			log.info(msg);
		} else {
			log.error(errormsg);
			throw new BaseException(errormsg);
		}
	}
	
	public String getExceptionMessage() {
		return exceptionMessage;
	}


	public void setExceptionMessage(String actualValue,String expectValue) {
		this.exceptionMessage = "expectedValue doesn't match actualValue,actual Value is :"
				+ actualValue+"; expected Value is :" + expectValue;
	}

	/**
	 * @return the message
	 */
	public String getMessage() {
		return message;
	}


	public void setMessage(String expectValue, String actualValue) {
		this.message = "expectedValue :" + expectValue + "  match actualValue:"
				+ actualValue;
	}

	/**
	 * @return the actualValue
	 */
	public String getActualValue() {
		return actualValue;
	}

	/**
	 * @param actualValue
	 *            the actualValue to set
	 */
	public void setActualValue(String actualValue) {
		this.actualValue = actualValue;
	}

	/**
	 * @return the expectValue
	 */
	public String getExpectValue() {
		return expectValue;
	}

	private Wait getLengthCheckingWait(final WebDriver driver) {
		return new Wait() {
			private int length;
			private long seenAt;

			@Override
			public boolean until() {
				// Page length needs to be stable for a second
				try {
					int currentLength = driver.findElement(By.tagName("body"))
							.getText().length();
					if (seenAt == 0) {
						seenAt = System.currentTimeMillis();
						length = currentLength;
						return false;
					}

					if (currentLength != length) {
						seenAt = System.currentTimeMillis();
						length = currentLength;
						return false;
					}

					return System.currentTimeMillis() - seenAt > 1000;
				} catch (NoSuchElementException ignored) {
				} catch (NullPointerException ignored) {
				}

				return false;
			}
		};
	}

}
